#!/usr/bin/env python3
"""
修复 stale element reference 错误的脚本
主要问题：在View Specifications导航后，原来的DOM元素变成stale，需要重新获取
"""

import time
from selenium import webdriver
from selenium.webdriver.common.by import By
from selenium.webdriver.support.ui import WebDriverWait
from selenium.webdriver.support import expected_conditions as EC
from selenium.webdriver.chrome.service import Service
from selenium.webdriver.chrome.options import Options
from webdriver_manager.chrome import ChromeDriverManager
from selenium.webdriver.common.action_chains import ActionChains

def setup_driver():
    """设置WebDriver"""
    chrome_options = Options()
    chrome_options.add_argument('--headless')
    chrome_options.add_argument('--no-sandbox')
    chrome_options.add_argument('--disable-dev-shm-usage')
    chrome_options.add_argument('--disable-web-security')
    chrome_options.add_argument('--disable-features=VizDisplayCompositor')
    chrome_options.add_argument('--window-size=1920,1080')
    chrome_options.add_argument('--user-agent=Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/119.0.0.0 Safari/537.36')
    
    driver = webdriver.Chrome(
        service=Service(ChromeDriverManager().install()),
        options=chrome_options
    )
    return driver

def get_fresh_model_elements(driver):
    """重新获取新的车型元素，避免stale element错误"""
    try:
        # 等待页面稳定
        WebDriverWait(driver, 10).until(
            EC.presence_of_element_located((By.CSS_SELECTOR, 'div[data-cy][class*="ProductTile"]'))
        )
        
        elements = driver.find_elements(By.CSS_SELECTOR, 'div[data-cy][class*="ProductTile"]')
        print(f"重新获取到 {len(elements)} 个车型元素")
        
        # 返回元素的基本信息，而不是元素对象本身
        model_info = []
        for i, element in enumerate(elements):
            try:
                data_cy = element.get_attribute('data-cy')
                is_displayed = element.is_displayed()
                model_info.append({
                    'index': i,
                    'data_cy': data_cy,
                    'is_displayed': is_displayed
                })
            except Exception as e:
                print(f"获取第{i+1}个元素信息失败: {e}")
                continue
        
        return model_info
    except Exception as e:
        print(f"重新获取车型元素失败: {e}")
        return []

def extract_single_model_safe(driver, model_index, data_cy):
    """安全地提取单个车型数据，每次重新获取元素"""
    try:
        print(f"\n🚗 开始处理第 {model_index + 1} 个车型: {data_cy}")
        
        # 重新获取所有车型元素
        elements = driver.find_elements(By.CSS_SELECTOR, 'div[data-cy][class*="ProductTile"]')
        
        if model_index >= len(elements):
            print(f"❌ 索引 {model_index} 超出范围，当前只有 {len(elements)} 个元素")
            return None
        
        element = elements[model_index]
        
        # 验证这是正确的元素
        current_data_cy = element.get_attribute('data-cy')
        if current_data_cy != data_cy:
            print(f"⚠️  元素不匹配: 期望 {data_cy}, 实际 {current_data_cy}")
            return None
        
        # 提取基本信息
        name_elements = element.find_elements(By.CSS_SELECTOR, 'strong[class*="ProductTileAttributeValue"]')
        
        model_name = None
        price = None
        
        for name_elem in name_elements:
            text = name_elem.text.strip()
            if text.startswith('£'):
                price = text
            elif text and not text.startswith('£') and not model_name:
                model_name = text
        
        if not model_name:
            model_name = data_cy
        
        print(f"基本信息: {model_name} - {price}")
        
        # 获取Key Features
        key_features = get_key_features_safe(driver, model_index, data_cy, model_name)
        
        return {
            "model_name": model_name,
            "price": price,
            "Key Features": key_features
        }
        
    except Exception as e:
        print(f"处理车型 {data_cy} 时出错: {e}")
        return None

def get_key_features_safe(driver, model_index, data_cy, model_name):
    """安全地获取Key Features，处理导航后的页面状态"""
    try:
        print(f"    🔍 获取 {model_name} 的Key Features...")
        
        # 重新获取元素
        elements = driver.find_elements(By.CSS_SELECTOR, 'div[data-cy][class*="ProductTile"]')
        if model_index >= len(elements):
            print(f"    ❌ 重新获取元素失败，索引超出范围")
            return []
        
        element = elements[model_index]
        
        # 滚动到元素并悬停
        driver.execute_script("arguments[0].scrollIntoView({block: 'center'});", element)
        time.sleep(0.5)
        
        actions = ActionChains(driver)
        actions.move_to_element(element).perform()
        time.sleep(1.5)
        
        # 查找View Specifications按钮
        spec_button = None
        try:
            buttons = element.find_elements(By.CSS_SELECTOR, 'button[data-cy="product-tile-overlay"]')
            if buttons:
                spec_button = buttons[0]
                print(f"    ✓ 找到View Specifications按钮")
            else:
                print(f"    ❌ 未找到View Specifications按钮")
                return []
        except Exception as e:
            print(f"    ❌ 查找按钮失败: {e}")
            return []
        
        # 点击按钮
        try:
            original_url = driver.current_url
            spec_button.click()
            print(f"    🖱️  已点击View Specifications按钮")
            
            # 等待页面变化或模态框出现
            time.sleep(3)
            
            # 尝试提取Key Features
            key_features = extract_key_features_from_modal(driver)
            
            # 导航回原页面
            if driver.current_url != original_url:
                print(f"    🔄 导航回原页面...")
                driver.get(original_url)
                # 等待页面重新加载
                WebDriverWait(driver, 10).until(
                    EC.presence_of_element_located((By.CSS_SELECTOR, 'div[data-cy][class*="ProductTile"]'))
                )
                time.sleep(2)
            
            return key_features
            
        except Exception as e:
            print(f"    ❌ 点击按钮或提取Features失败: {e}")
            return []
    
    except Exception as e:
        print(f"    ❌ 获取Key Features时出错: {e}")
        return []

def extract_key_features_from_modal(driver):
    """从模态框或新页面中提取Key Features"""
    try:
        # 等待内容加载
        time.sleep(2)
        
        # 主要选择器
        selectors = [
            'dl[data-testid="Key_Features_ID"]',
            'dl[data-testid*="Key_Features"]',
            'section[data-testid*="key-features"] dt',
            'div[class*="KeyFeatures"] dt',
            '[data-testid*="features"] dt'
        ]
        
        key_features = []
        
        for selector in selectors:
            try:
                elements = driver.find_elements(By.CSS_SELECTOR, selector)
                if elements:
                    print(f"    ✓ 使用选择器 {selector} 找到 {len(elements)} 个特性")
                    for elem in elements:
                        text = elem.text.strip()
                        if text and text not in key_features:
                            key_features.append(text)
                    if key_features:
                        break
            except Exception:
                continue
        
        # 如果主要选择器失败，尝试广泛搜索
        if not key_features:
            try:
                # 搜索页面中所有dt元素
                dt_elements = driver.find_elements(By.CSS_SELECTOR, 'dt')
                for dt in dt_elements:
                    text = dt.text.strip()
                    if (text and len(text) > 5 and len(text) < 100 and
                        not any(skip in text.lower() for skip in ['price', 'total', 'monthly', 'deposit'])):
                        key_features.append(text)
                
                print(f"    ✓ 通过广泛搜索找到 {len(key_features)} 个特性")
            except Exception as e:
                print(f"    ❌ 广泛搜索失败: {e}")
        
        return key_features[:5]  # 限制返回前5个
        
    except Exception as e:
        print(f"提取Key Features失败: {e}")
        return []

def test_stale_element_fix():
    """测试修复stale element问题的方法"""
    driver = setup_driver()
    
    try:
        url = "https://www.ford.co.uk/shop/build-your-ford/ngc2/ice2/model?catalogId=WAEGB-CGE-2022-FocusMCAGBR202450&series=ACMAA_VS-DH&planId=c"
        
        print("🌐 访问页面...")
        driver.get(url)
        
        # 等待页面加载
        WebDriverWait(driver, 15).until(
            EC.presence_of_element_located((By.CSS_SELECTOR, 'div[data-cy][class*="ProductTile"]'))
        )
        time.sleep(3)
        
        # 获取初始车型信息
        model_info_list = get_fresh_model_elements(driver)
        print(f"\n📋 发现 {len(model_info_list)} 个车型:")
        for info in model_info_list:
            print(f"  {info['index']+1}. {info['data_cy']} (显示: {info['is_displayed']})")
        
        # 逐个处理车型
        extracted_models = []
        for info in model_info_list:
            if info['is_displayed']:
                model_data = extract_single_model_safe(driver, info['index'], info['data_cy'])
                if model_data:
                    extracted_models.append(model_data)
                    print(f"    ✅ 成功提取: {model_data['model_name']}")
                else:
                    print(f"    ❌ 提取失败: {info['data_cy']}")
        
        print(f"\n🎯 总结:")
        print(f"  期望车型数: {len([info for info in model_info_list if info['is_displayed']])}")
        print(f"  成功提取数: {len(extracted_models)}")
        print(f"  成功率: {len(extracted_models)/len([info for info in model_info_list if info['is_displayed']]):.1%}")
        
        print(f"\n📊 提取结果:")
        for i, model in enumerate(extracted_models):
            features_count = len(model.get('Key Features', []))
            print(f"  {i+1}. {model['model_name']} - {model['price']} ({features_count} features)")
        
    except Exception as e:
        print(f"测试失败: {e}")
    
    finally:
        driver.quit()

if __name__ == "__main__":
    test_stale_element_fix()
